﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.ComponentModel;
using System.Web;

using Seven.Entity;
using Seven.EntityBasic;
using Seven.Core.IRepositories;
using Seven.MsSql.Context;
using Seven.Tools;
using Seven.Tools.Extension;
using Seven.Tools.Helper;
using Seven.Tools.ComponentModel.Paging;

namespace Seven.MsSql.Repositories
{
    /// <summary>
    /// 仓储基类
    /// </summary>
    /// <typeparam name="TEntity">实体类型</typeparam>
    /// <typeparam name="TKey">TEntity实体的主键类型</typeparam>
    public abstract class BaseRepository<TEntity, TKey> : IBaseRepository<TEntity, TKey>
        where TKey : struct
        where TEntity : EntityBase<TKey>, new()
    {
        private MethodInfo _orderByMethod;

        #region 属性

        #region private 私有，仅当前类可用

        private DbSet<TEntity> DbSet { get { return this.dbContext.Set<TEntity>(); } }

        #endregion

        #region protected 仅自己和派生类可用

        /// <summary>
        /// 数据上下文对象
        /// </summary>
        protected DbContext dbContext { get; set; }

        #endregion

        #endregion

        #region 构造方法

        public BaseRepository()
        { }

        /// <summary>
        /// 该构造方法仅在仓储中被使用，因此设置访问修饰符为protected
        /// </summary>
        /// <param name="db">数据上下文</param>
        protected BaseRepository(DbContext db)
            : this()
        {
            this.dbContext = db;
        }

        #endregion

        #region 对接口的实现方法。公开，允许开放给其他项目调用

        /// <summary>
        /// 设置数据对象
        /// </summary>
        /// <param name="context">数据对象</param>
        public void SetContext(object context)
        {
            this.dbContext = context as DbContext;
        }

        /// <summary>
        /// 根据主键查询单个实体
        /// </summary>
        /// <param name="key">键值</param>
        /// <returns></returns>
        public virtual TEntity Find(TKey key)
        {
            return this.DbSet.Find(key).CopyByDelegate<TEntity, TKey>();
        }

        /// <summary>
        /// 根据主键集合批量查询实体 有问题!
        /// </summary>
        /// <param name="keyValues">主键集合</param>
        /// <returns>返回实体数组</returns>
        public virtual TEntity[] Select(IEnumerable<object> keyValues)
        {
            Check.NotEmpty(keyValues);
            IEnumerable<object> temps = keyValues.Where(keyValue => keyValue != null);

            DbSet<TEntity> set = this.DbSet;
            List<TEntity> list = new List<TEntity>();
            foreach (object keyValue in temps)
            {
                TEntity entity = set.Find(keyValue);
                if (entity != null) { list.Add(entity); }
            }
            return list.Select(item => item.CopyByDelegate<TEntity, TKey>()).ToArray();
        }

        /// <summary>
        /// 根据主键集合批量查询实体 有问题!
        /// </summary>
        /// <param name="keyValues">主键集合</param>
        /// <returns>返回实体数组</returns>
        public virtual TEntity[] Select(params object[] keyValues)
        {
            return this.Select(keyValues.AsEnumerable());
        }

        #endregion

        #region 方法

        #region private 私有，仅当前类可用

        /// <summary>
        /// 获取静态类型 <see cref="Seven.Tools.Extension.QueryableExtensions"/> 中定义的
        ///     public static IOrderedQueryable&lt;TSource&gt; OrderBy&lt;TSource, TKey&gt;(IQueryable&lt;TSource&gt;, Expression&lt;Func&lt;TSource, TKey&gt;&gt;, ListSortDirection)
        ///     方法。
        /// </summary>
        private MethodInfo OrderByMethod
        {
            get
            {
                if (this._orderByMethod == null)
                {
                    this._orderByMethod = typeof(Seven.Tools.Extension.QueryableExtensions).GetMethods().First(m =>
                    {
                        if (m.Name != "OrderBy" || !m.IsGenericMethod)
                        { return false; }
                        ParameterInfo[] parameters = m.GetParameters();
                        return parameters.Length == 3 && parameters[2].ParameterType == typeof(ListSortDirection);
                    });
                }
                return this._orderByMethod;
            }
        }

        /// <summary>
        /// 根据 <see cref="propertyOrFieldName"/> 参数所示的字段对查询进行排序操作。
        /// </summary>
        /// <param name="queryable"></param>
        /// <param name="propertyOrFieldName"></param>
        /// <param name="sortDirection"></param>
        /// <returns></returns>
        private IQueryable<TEntity> OrderBy(IQueryable<TEntity> queryable, string propertyOrFieldName, ListSortDirection sortDirection)
        {
            Type entityType = typeof(TEntity);
            Type propertyOrFieldType = null;
            LambdaExpression expr = Expressions.Lambda(entityType, propertyOrFieldName, out propertyOrFieldType);
            MethodInfo orderbyMethod = this.OrderByMethod.MakeGenericMethod(entityType, propertyOrFieldType);
            return orderbyMethod.Invoke(null, new object[] { queryable, expr, sortDirection }) as IQueryable<TEntity>;
        }

        /// <summary>
        /// 新增或更新单个实体时对实体的基本属性自动赋值
        /// </summary>
        /// <param name="entity">目标实体对象</param>
        /// <param name="isUpdate">是否更新动作，默认为false，即默认为新增动作</param>
        private static void SetBaseProperty(TEntity entity, bool isUpdate = false)
        {
            var current = HttpContext.Current;
            string CurrentUserName = current.User.Identity.IsAuthenticated ? current.User.Identity.Name : "test";
            if (entity is EntityBase<TKey>)
            {
                if (!isUpdate)
                {
                    #region 新增时
                    if (typeof(TKey) == typeof(Guid))
                    {
                        var BaseData = entity as EntityBase<Guid>;
                        BaseData.ID = Guid.NewGuid();
                        if (string.IsNullOrWhiteSpace(BaseData.CreateUserName))
                        {
                            BaseData.CreateUserName = CurrentUserName;
                            BaseData.CreateDate = DateTime.Now;
                        }
                    }
                    else
                    {
                        var BaseData = (EntityBase<TKey>)entity;
                        if (string.IsNullOrWhiteSpace(BaseData.CreateUserName))
                        {
                            BaseData.CreateUserName = CurrentUserName;
                            BaseData.CreateDate = DateTime.Now;
                        }
                    }
                    #endregion
                }
                else
                {
                    #region 更新时
                    var BaseData = (EntityBase<TKey>)entity;
                    BaseData.LastModifyUserName = CurrentUserName;
                    BaseData.LastModifyDate = DateTime.Now;
                    #endregion
                }
            }
        }

        /// <summary>
        /// 新增或更新实体集合时对每个实体的基本属性自动赋值
        /// </summary>
        /// <param name="entities">目标实体对象集合</param>
        /// <param name="isUpdate">是否更新动作，默认为false，即默认为新增动作</param>
        private static void SetBaseProperty(IEnumerable<TEntity> entities, bool isUpdate = false)
        {
            var current = HttpContext.Current;
            string CurrentUserName = current.User.Identity.IsAuthenticated ? current.User.Identity.Name : "test";

            foreach (var entity in entities)
            {
                if (entity is EntityBase<TKey>)
                {
                    if (!isUpdate)
                    {
                        #region 新增时
                        if (typeof(TKey) == typeof(Guid))
                        {
                            var BaseData = entity as EntityBase<Guid>;
                            BaseData.ID = Guid.NewGuid();
                            if (string.IsNullOrWhiteSpace(BaseData.CreateUserName))
                            {
                                BaseData.CreateUserName = CurrentUserName;
                                BaseData.CreateDate = DateTime.Now;
                            }
                        }
                        else
                        {
                            var BaseData = (EntityBase<TKey>)entity;
                            if (string.IsNullOrWhiteSpace(BaseData.CreateUserName))
                            {
                                BaseData.CreateUserName = CurrentUserName;
                                BaseData.CreateDate = DateTime.Now;
                            }
                        }
                        #endregion
                    }
                    else
                    {
                        #region 更新时
                        var BaseData = (EntityBase<TKey>)entity;
                        BaseData.LastModifyUserName = CurrentUserName;
                        BaseData.LastModifyDate = DateTime.Now;
                        #endregion
                    }
                }
            }
        }

        /// <summary>
        /// 根据匿名对象组建SqlParameter对象集合
        /// { Value = 1 } 转换成 new SqlParameter[]{ new SqlParameter("@Value", 1) }
        /// { Value = 1, Name = "XX" } 转换成 new SqlParameter[]{ new SqlParameter("@Value", 1),new SqlParameter("@Name", "XX") }
        /// </summary>
        /// <param name="param">匿名对象</param>
        private static System.Data.SqlClient.SqlParameter[] BuildSqlParameter(object param)
        {
            if (param == null) { return null; }
            List<System.Data.SqlClient.SqlParameter> p = new List<System.Data.SqlClient.SqlParameter>();
            var T = param.GetType();
            foreach (var item in T.GetProperties())
            {
                p.Add(new System.Data.SqlClient.SqlParameter { ParameterName = item.Name, Value = item.GetValue(param,null) });
            }
            return p.ToArray();
        }

        #endregion

        #region internal 仅当前项目中可用

        /// <summary>
        /// 数据查询器
        /// </summary>
        /// <returns></returns>
        internal IQueryable<TEntity> Entities()
        {
            return this.DbSet.AsNoTracking();
        }

        #endregion

        #region protected 仅自己和派生类可用

        #region 数据查询

        #region 查询单个实体

        /// <summary>
        /// 根据条件表达式查询单个实体
        /// </summary>
        /// <param name="predicate">条件表达式</param>
        /// <returns></returns>
        protected virtual TEntity GetSingle(Expression<Func<TEntity, bool>> predicate)
        {
            Check.NotNull(predicate);
            return this.DbSet.Where(predicate).FirstOrDefault().CopyByDelegate<TEntity, TKey>();
        }

        /// <summary>
        /// 根据条件表达式查询单个实体，支持排序
        /// </summary>
        /// <param name="predicate">条件表达式</param>
        /// <param name="keySelector">排序字段</param>
        /// <param name="sortDirection">排序方式</param>
        /// <returns></returns>
        protected virtual TEntity GetSingle(Expression<Func<TEntity, bool>> predicate, string keySelector, ListSortDirection sortDirection = ListSortDirection.Ascending)
        {
            Check.NotNull(predicate);
            Check.NotEmpty(keySelector);
            IQueryable<TEntity> queryable = this.DbSet.Where(predicate);
            return this.OrderBy(queryable, keySelector, sortDirection).FirstOrDefault().CopyByDelegate<TEntity, TKey>();
        }

        /// <summary>
        /// 根据条件表达式查询单个实体，支持排序
        /// </summary>
        /// <typeparam name="OKey">由 keySelector 表示的函数返回的键类型。</typeparam>
        /// <param name="predicate">条件表达式</param>
        /// <param name="keySelector">排序表达式</param>
        /// <param name="sortDirection">排序方式</param>
        /// <returns></returns>
        protected virtual TEntity GetSingle<OKey>(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, OKey>> keySelector, ListSortDirection sortDirection = ListSortDirection.Ascending)
        {
            Check.NotNull(predicate);
            Check.NotNull(keySelector);
            return this.DbSet.Where(predicate).OrderBy(keySelector, sortDirection).FirstOrDefault().CopyByDelegate<TEntity, TKey>();
        }

        #endregion

        #region 查询多个实体

        /// <summary>
        /// 根据条件表达式批量查询实体
        /// </summary>
        /// <param name="predicate">条件表达式</param>
        /// <returns>返回实体数组</returns>
        protected virtual TEntity[] Get(Expression<Func<TEntity, bool>> predicate)
        {
            Check.NotNull(predicate);
            return this.DbSet.Where(predicate).ToArray().Select(item => item.CopyByDelegate<TEntity, TKey>()).ToArray();
        }

        /// <summary>
        /// 根据条件表达式批量查询实体，支持排序
        /// </summary>
        /// <param name="predicate">条件表达式</param>
        /// <param name="keySelector">排序字段</param>
        /// <param name="sortDirection">排序方式</param>
        /// <returns>返回实体数组</returns>
        protected virtual TEntity[] Get(Expression<Func<TEntity, bool>> predicate, string keySelector, ListSortDirection sortDirection = ListSortDirection.Ascending)
        {
            Check.NotNull(predicate);
            Check.NotEmpty(keySelector);
            IQueryable<TEntity> queryable = this.DbSet.Where(predicate);
            return this.OrderBy(queryable, keySelector, sortDirection).ToArray().Select(item => item.CopyByDelegate<TEntity, TKey>()).ToArray();
        }

        /// <summary>
        /// 根据条件表达式批量查询实体，支持排序
        /// </summary>
        /// <typeparam name="OKey">由 keySelector 表示的函数返回的键类型。</typeparam>
        /// <param name="predicate">条件表达式</param>
        /// <param name="keySelector">排序字段</param>
        /// <param name="sortDirection">排序方式</param>
        /// <returns>返回实体数组</returns>
        protected virtual TEntity[] Get<OKey>(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, OKey>> keySelector, ListSortDirection sortDirection = ListSortDirection.Ascending)
        {
            Check.NotNull(predicate);
            Check.NotNull(keySelector);
            return this.DbSet.Where(predicate).OrderBy(keySelector, sortDirection).ToArray().Select(item => item.CopyByDelegate<TEntity, TKey>()).ToArray();
        }

        #endregion

        #region 查询是否存在记录

        /// <summary>
        /// 根据指定的条件表达式判断符合条件的记录是否存在
        /// </summary>
        /// <param name="predicate">条件表达式</param>
        /// <returns>存在记录，返回 true 。不存在记录，则返回 false 。</returns>
        protected virtual bool Any(Expression<Func<TEntity, bool>> predicate)
        {
            return this.DbSet.Any(predicate);
        }

        #endregion

        #region 查询最大值

        /// <summary>
        /// 根据指定的条件表达式和指定的Max对象表达式返回最大结果值
        /// </summary>
        /// <typeparam name="TResult">返回类型</typeparam>
        /// <param name="predicate">条件表达式</param>
        /// <param name="selector">要应用于每个元素的投影函数。</param>
        /// <returns>序列中的最大值</returns>
        protected virtual TResult Max<TResult>(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, TResult>> selector)
        {
            return this.DbSet.Where(predicate).Max(selector);
        }

        #endregion

        #region 查询数量

        /// <summary>
        /// 根据指定的条件表达式返回符合条件的记录的数量
        /// </summary>
        /// <param name="predicate">条件表达式</param>
        /// <returns></returns>
        protected virtual int Count(Expression<Func<TEntity, bool>> predicate)
        {
            return this.DbSet.Count(predicate);
        }

        #endregion

        #endregion

        #region 分页查询，该封装其实没什么用，因为不太可能对指定实体对象进行分页查询

        protected virtual TEntity[] SelectPage(int pageIndex, int pageSize)
        {
            return this.DbSet.OrderBy(o => o.ID).SplitPage(pageIndex, pageSize).ToArray().Select(item => item.CopyByDelegate<TEntity, TKey>()).ToArray();
        }

        protected virtual TEntity[] SelectPage(int pageIndex, int pageSize, string keySelector, ListSortDirection sortDirection = ListSortDirection.Ascending)
        {
            Check.NotEmpty(keySelector);

            return this.OrderBy(this.DbSet, keySelector, sortDirection).SplitPage(pageIndex, pageSize).ToArray().Select(item => item.CopyByDelegate<TEntity, TKey>()).ToArray();
        }

        protected virtual TEntity[] SelectPage<OKey>(int pageIndex, int pageSize, Expression<Func<TEntity, OKey>> keySelector, ListSortDirection sortDirection = ListSortDirection.Ascending)
        {
            Check.NotNull(keySelector);
            return this.DbSet.OrderBy(keySelector, sortDirection).SplitPage(pageIndex, pageSize).ToArray().Select(item => item.CopyByDelegate<TEntity, TKey>()).ToArray();
        }

        protected virtual TEntity[] SelectPage(Expression<Func<TEntity, bool>> predicate, int pageIndex, int pageSize)
        {
            Check.NotNull(predicate);
            return this.DbSet.Where(predicate).SplitPage(pageIndex, pageSize).ToArray().Select(item => item.CopyByDelegate<TEntity, TKey>()).ToArray();
        }

        protected virtual TEntity[] SelectPage(Expression<Func<TEntity, bool>> predicate, int pageIndex, int pageSize, string keySelector, ListSortDirection sortDirection = ListSortDirection.Ascending)
        {
            Check.NotNull(predicate);
            Check.NotEmpty(keySelector);
            IQueryable<TEntity> queryable = this.DbSet.Where(predicate);
            return this.OrderBy(queryable, keySelector, sortDirection).SplitPage(pageIndex, pageSize).ToArray().Select(item => item.CopyByDelegate<TEntity, TKey>()).ToArray();
        }

        protected virtual TEntity[] SelectPage<OKey>(Expression<Func<TEntity, bool>> predicate, int pageIndex, int pageSize, Expression<Func<TEntity, OKey>> keySelector, ListSortDirection sortDirection = ListSortDirection.Ascending)
        {
            Check.NotNull(predicate);
            Check.NotNull(keySelector);
            return this.DbSet.Where(predicate).OrderBy(keySelector, sortDirection).SplitPage(pageIndex, pageSize).ToArray().Select(item => item.CopyByDelegate<TEntity, TKey>()).ToArray();
        }

        protected virtual PagingData<TEntity> SelectPaging(int pageIndex, int pageSize)
        {
            PagingData<TEntity> data = this.DbSet.OrderBy(o => o.ID).ToPagingData(pageIndex, pageSize);
            data.Data = data.Data.Select(item => item.Duplicate());
            return data;
        }

        #endregion

        #region 直接执行Sql

        /// <summary>
        /// 直接执行SQL语句，返回影响的行数
        /// </summary>
        /// <param name="sql">SQL语句</param>
        /// <param name="param">参数</param>
        /// <returns></returns>
        protected int ExecSqlCommand(string sql, object param)
        {
            var p = BuildSqlParameter(param);
            try
            {
                return p == null ? this.dbContext.Database.ExecuteSqlCommand(sql) : this.dbContext.Database.ExecuteSqlCommand(sql, p);
            }
            catch (Exception e)
            {
                throw ExceptionHelper.ThrowDataAccessException(e.Message);
            }
            
        }

        /// <summary>
        /// 直接执行SQL语句，返回影响的行数
        /// </summary>
        /// <param name="useTransaction">是否自动使用新事务进行操作</param>
        /// <param name="sql">SQL语句</param>
        /// <param name="param">参数</param>
        /// <returns></returns>
        protected int ExecSqlCommand(bool useTransaction, string sql, object param)
        {
            var p = BuildSqlParameter(param);
            try
            {
                TransactionalBehavior temp = useTransaction ? TransactionalBehavior.EnsureTransaction : TransactionalBehavior.DoNotEnsureTransaction;
                if (p == null)
                { 
                    return this.dbContext.Database.ExecuteSqlCommand(temp, sql);
                }
                else{
                    return this.dbContext.Database.ExecuteSqlCommand(temp, sql, p);
                }
            }
            catch (Exception e)
            {
                throw ExceptionHelper.ThrowDataAccessException(e.Message);
            }
        }

        /// <summary>
        /// 根据sql语句查询，返回的数据集合不受EF跟踪。需指定返回的模型类型，该类型不必是实体类型。
        /// </summary>
        /// <typeparam name="TModel">模型类型，该类型不必是实体类型</typeparam>
        /// <param name="sql">SQL语句</param>
        /// <param name="param">参数</param>
        /// <returns></returns>
        protected IEnumerable<TModel> DbSqlQuery<TModel>(string sql, object param)
        {
            var p = BuildSqlParameter(param);
            try
            {
                return p == null ? this.dbContext.Database.SqlQuery<TModel>(sql) : this.dbContext.Database.SqlQuery<TModel>(sql, p);
            }
            catch (Exception e)
            {
                throw ExceptionHelper.ThrowDataAccessException(e.Message);
            }
        }

        /// <summary>
        /// 根据sql语句查询实体集合，返回的实体集合受EF跟踪。注意返回实体的类型始终是TEntity的集合，若多表查询，请编写适当的sql查询以确保只返回适当类型的实体。
        /// </summary>
        /// <param name="sql">SQL语句</param>
        /// <param name="param">参数</param>
        /// <returns></returns>
        protected IEnumerable<TEntity> DbSetSqlQuery(string sql, object param)
        {
            var p = BuildSqlParameter(param);
            try
            {
                return p == null ? this.DbSet.SqlQuery(sql) : this.DbSet.SqlQuery(sql, p);
            }
            catch (Exception e)
            {
                throw ExceptionHelper.ThrowDataAccessException(e.Message);
            }
        }

        /// <summary>
        /// 根据sql语句查询实体集合，返回的实体集合不受EF跟踪。注意返回实体的类型始终是TEntity的集合，若多表查询，请编写适当的sql查询以确保只返回适当类型的实体。
        /// </summary>
        /// <param name="sql">SQL语句</param>
        /// <param name="param">参数</param>
        /// <returns></returns>
        protected IEnumerable<TEntity> DbSetSqlQueryNoTracking(string sql, object param)
        {
            var p = BuildSqlParameter(param);
            try
            {
                return p == null ? this.DbSet.SqlQuery(sql).AsNoTracking() : this.DbSet.SqlQuery(sql, p).AsNoTracking();
            }
            catch (Exception e)
            {
                throw ExceptionHelper.ThrowDataAccessException(e.Message);
            }
        }

        #endregion

        #region 数据操作

        #region 添加

        /// <summary>
        /// 添加实体
        /// </summary>
        /// <param name="entity">实体</param>
        public virtual void EntityAdded(TEntity entity)
        {
            if (entity == null)
                return;
            SetBaseProperty(entity, false);

            this.DbSet.Add(entity);
        }

        /// <summary>
        /// 批量添加实体
        /// </summary>
        /// <param name="entities">实体集合</param>
        public virtual void EntitiesAdded(IEnumerable<TEntity> entities)
        {
            if (entities == null || entities.Count() == 0)
            { return; }

            SetBaseProperty(entities, false);

            DbSet<TEntity> set = this.DbSet;

            bool autoDetectChangesEnabled = this.dbContext.Configuration.AutoDetectChangesEnabled;
            this.dbContext.Configuration.AutoDetectChangesEnabled = false;

            foreach (TEntity entity in entities)
            {
                if (entity == null)
                { continue; }
                set.Add(entity);
            }

            this.dbContext.Configuration.AutoDetectChangesEnabled = autoDetectChangesEnabled;
        }

        #endregion

        #region 更改

        /// <summary>
        /// 更改实体
        /// </summary>
        /// <param name="entity">实体</param>
        public virtual void EntityModified(TEntity entity)
        {
            SetBaseProperty(entity, true);

            TEntity temp = entity.DuplicateWithNonNavigationProperties<TEntity, TKey>(this.dbContext);

            DbEntityEntry<TEntity> entry = this.dbContext.FindEntry<TEntity, TKey>(temp);
            if (entry.State == EntityState.Detached)
            {
                this.DbSet.Attach(temp);
            }
            entry.State = EntityState.Modified;
        }

        /// <summary>
        /// 批量更改实体
        /// </summary>
        /// <param name="entities">实体集合</param>
        public virtual void EntitiesModified(IEnumerable<TEntity> entities)
        {
            if (entities == null || entities.Count() == 0)
            { return; }

            SetBaseProperty(entities, false);

            DbSet<TEntity> set = this.DbSet;
            bool autoDetectChangesEnabled = this.dbContext.Configuration.AutoDetectChangesEnabled;
            this.dbContext.Configuration.AutoDetectChangesEnabled = false;

            foreach (TEntity entity in entities)
            {
                TEntity entityCopy = entity.DuplicateWithNonNavigationProperties<TEntity, TKey>(this.dbContext);
                DbEntityEntry<TEntity> entry = this.dbContext.FindEntry<TEntity, TKey>(entityCopy);
                if (entry.State == EntityState.Detached)
                {
                    set.Attach(entityCopy);
                }
                entry.State = EntityState.Modified;
            }

            this.dbContext.Configuration.AutoDetectChangesEnabled = autoDetectChangesEnabled;
        }

        #endregion

        #region 删除

        /// <summary>
        /// 主键删除实体
        /// </summary>
        /// <param name="key">键值</param>
        public virtual void EntityDeleted(TKey key)
        {
            DbSet<TEntity> set = this.DbSet;
            TEntity entity = set.Find(key);

            if (entity != null)
            {
                set.Remove(entity);
            }
        }

        /// <summary>
        /// 删除实体
        /// </summary>
        /// <param name="entity">实体</param>
        public virtual void EntityDeleted(TEntity entity)
        {
            if (entity == null)
            { return; }
            TEntity temp = entity.DuplicateWithNonNavigationProperties<TEntity, TKey>(this.dbContext);

            DbSet<TEntity> set = this.DbSet;
            DbEntityEntry<TEntity> entry = this.dbContext.FindEntry<TEntity, TKey>(temp);
            if (entry.State == EntityState.Detached)
            {
                set.Attach(temp);
            }
            set.Remove(temp);
        }

        /// <summary>
        /// 批量删除实体
        /// </summary>
        /// <param name="entities">实体</param>
        public virtual void EntitiesDeleted(IEnumerable<TEntity> entities)
        {
            if (entities == null || entities.Count() == 0)
            { return; }

            DbSet<TEntity> set = this.DbSet;
            bool autoDetectChangesEnabled = this.dbContext.Configuration.AutoDetectChangesEnabled;
            this.dbContext.Configuration.AutoDetectChangesEnabled = false;

            foreach (TEntity entity in entities)
            {
                var entityCopy = entity.DuplicateWithNonNavigationProperties<TEntity, TKey>(this.dbContext);
                DbEntityEntry<TEntity> entry = this.dbContext.FindEntry<TEntity, TKey>(entityCopy);
                if (entry.State == EntityState.Detached)
                {
                    set.Attach(entityCopy);
                }
                set.Remove(entityCopy);
            }

            this.dbContext.Configuration.AutoDetectChangesEnabled = autoDetectChangesEnabled;
        }

        /// <summary>
        /// 根据条件删除实体
        /// </summary>
        /// <param name="predicate">查询条件</param>
        public virtual void EntitiesDeleted(Expression<Func<TEntity, bool>> predicate)
        {
            DbSet<TEntity> set = this.DbSet;
            var entities = set.Where(predicate);

            if (entities == null || entities.Count() == 0)
            { return; }

            bool autoDetectChangesEnabled = this.dbContext.Configuration.AutoDetectChangesEnabled;
            this.dbContext.Configuration.AutoDetectChangesEnabled = false;

            set.RemoveRange(entities);

            this.dbContext.Configuration.AutoDetectChangesEnabled = autoDetectChangesEnabled;
        }

        #endregion

        #endregion

        #region 智能查询的条件组装

        /// <summary>
        /// 将string格式的约定查询条件转化成查询条件模型对象
        /// </summary>
        /// <param name="model">string格式的约定查询条件</param>
        /// <returns></returns>
        protected Seven.Web.IntelligentQuery.Model.QueryModel ConvertQueryModel(string model)
        {
            return Seven.Web.IntelligentQuery.Converter.QueryConverter.ToQueryModel(model);
        }

        /// <summary>
        /// 将string格式的约定查询条件转化成查询条件模型对象，同时将其中常规的参数组装成Dictionary以输出参数返回
        /// </summary>
        /// <param name="model">string格式的约定查询条件</param>
        /// <param name="dic">常规格式的查询条件组装成Dictionary以输出参数返回，Key是参数名，Value是参数值</param>
        /// <returns></returns>
        protected Seven.Web.IntelligentQuery.Model.QueryModel ConvertQueryModel(string model, ref Dictionary<string, string> dic)
        {
            return Seven.Web.IntelligentQuery.Converter.QueryConverter.ToQueryModel(model, ref dic);
        }

        #endregion

        #endregion

        #endregion
    }
}
